﻿using System;
using System.Diagnostics;
using System.IO;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Storage;

namespace StorageDemo {

	public class SavedGameManager {
		
		private StorageDevice StorageDevice;
		private IAsyncResult IAsynchResult;
		private Object StateObject;
		private bool GameSaveRequested;
		private SaveGameData SaveGameData;

		public SavedGameManager() {
			// ...
		}

		public void RequestGameSave(SaveGameData saveGameData) {
			if ((!Guide.IsVisible) && (!GameSaveRequested)) {
				GameSaveRequested = true;
				SaveGameData = saveGameData;
				IAsynchResult = StorageDevice.BeginShowSelector(PlayerIndex.One, null, null);
			}
		}

		public void ResetStorageDevice() {
			if (!Guide.IsVisible) {
				StorageDevice = null;
				StateObject = "GetDevice for Player One";
				StorageDevice.BeginShowSelector(PlayerIndex.One, GetDevice, StateObject);
			}
		}

		public void SaveIfPendingAndStorageDeviceChosen() {
			if ((GameSaveRequested) && (IAsynchResult.IsCompleted)) {
				StorageDevice = StorageDevice.EndShowSelector(IAsynchResult);
				if (StorageDevice != null && StorageDevice.IsConnected) {
					DoSaveGame(StorageDevice);
					//DoLoadGame(StorageDevice);
					//DoCreate(StorageDevice);
					//DoOpen(StorageDevice);
					//DoCopy(StorageDevice);
					//DoEnumerate(StorageDevice);
					//DoRename(StorageDevice);
					//DoDelete(StorageDevice);
					//DoOpenFile();
				}
				// Reset the request flag.
				GameSaveRequested = false;
			}
		}

		private void GetDevice(IAsyncResult result) {
			StorageDevice = StorageDevice.EndShowSelector(result);
			//if (StorageDevice != null && StorageDevice.IsConnected) {
			//    DoSaveGame(StorageDevice);
			//    DoLoadGame(StorageDevice);
			//    DoCreate(StorageDevice);
			//    DoOpen(StorageDevice);
			//    DoCopy(StorageDevice);
			//    DoEnumerate(StorageDevice);
			//    DoRename(StorageDevice);
			//    DoDelete(StorageDevice);
			//    DoOpenFile();
			//}
		}

		//=====( Begin Saved Games )===============================================================

		private void DoSaveGame(StorageDevice device) {
			// Open a storage container.
			IAsyncResult result = device.BeginOpenContainer("StorageDemo", null, null);

			// Wait for the WaitHandle to become signaled.
			result.AsyncWaitHandle.WaitOne();

			StorageContainer container = device.EndOpenContainer(result);

			// Close the wait handle.
			result.AsyncWaitHandle.Close();

			string fileName = string.Format("SavedGame "+"{0}.sav", DateTime.Now.ToString().Replace('/', '.').Replace(':','.'));
			Debug.WriteLine(fileName);

			// Check to see whether the save exists.
			if (container.FileExists(fileName)) {
				// Delete it so that we can create one fresh.
				container.DeleteFile(fileName);
			}

			// Create the file.
			Stream stream = container.CreateFile(fileName);

			// Convert the object to XML data and put it in the stream.
			XmlSerializer serializer = new XmlSerializer(typeof (SaveGameData));
			serializer.Serialize(stream, SaveGameData);

			// Close the file.
			stream.Close();

			// Dispose the container, to commit changes.
			container.Dispose();
		}

		/// <summary>
		/// This method loads a serialized data object from the StorageContainer for this game.
		/// </summary>
		public void DoLoadGame(StorageDevice device, string fileName) {
			// Open a storage container.
			IAsyncResult result = device.BeginOpenContainer("StorageDemo", null, null);

			// Wait for the WaitHandle to become signaled.
			result.AsyncWaitHandle.WaitOne();

			StorageContainer container = device.EndOpenContainer(result);

			// Close the wait handle.
			result.AsyncWaitHandle.Close();

			// Check to see whether the save exists.
			if (!container.FileExists(fileName)) {
				// If not, dispose of the container and return.
				container.Dispose();
				return;
			}

			// Open the file.
			Stream stream = container.OpenFile(fileName, FileMode.Open);

			// Read the data from the file.
			XmlSerializer serializer = new XmlSerializer(typeof (SaveGameData));
			SaveGameData data = (SaveGameData) serializer.Deserialize(stream);

			// Close the file.
			stream.Close();

			// Dispose the container.
			container.Dispose();

			// Report the data to the console.
			Debug.WriteLine("Name:     "+data.PlayerName);
			Debug.WriteLine("Level:    "+data.Level);
			Debug.WriteLine("Score:    "+data.Score);
			Debug.WriteLine("Position: "+data.AvatarPosition);
		}

		/// <summary>
		/// This method illustrates how to enumerate files in a StorageContainer.
		/// </summary>
		public void DoEnumerate() {
			IAsyncResult result = StorageDevice.BeginOpenContainer("StorageDemo", null, null);

			// Wait for the WaitHandle to become signaled.
			result.AsyncWaitHandle.WaitOne();

			StorageContainer container = StorageDevice.EndOpenContainer(result);

			// Close the wait handle.
			result.AsyncWaitHandle.Close();

			string[] FileList = container.GetFileNames();
			foreach (string filename in FileList) {
				Debug.WriteLine(filename);
			}

			// Dispose the container.
			container.Dispose();
		}

		//=====( End Saved Games )=================================================================
		///////////////////////////////////////////////////////////////////////////////////////////
		//=====( Begin Files )=====================================================================

		/// <summary>
		/// This method creates a file called demobinary.sav and places it in the StorageContainer for this game.
		/// </summary>
		private void DoCreate(StorageDevice device) {
			// Open a storage container.
			IAsyncResult result = device.BeginOpenContainer("StorageDemo", null, null);

			// Wait for the WaitHandle to become signaled.
			result.AsyncWaitHandle.WaitOne();

			StorageContainer container = device.EndOpenContainer(result);

			// Close the wait handle.
			result.AsyncWaitHandle.Close();

			// Add the container path to our file name.
			string filename = "demobinary.sav";

			// Create a new file.
			if (!container.FileExists(filename)) {
				Stream file = container.CreateFile(filename);
				file.Close();
			}
			// Dispose the container, to commit the data.
			container.Dispose();
		}

		/// <summary>
		/// This method illustrates how to open a file. It presumes that demobinary.sav has been created.
		/// </summary>
		private void DoOpen(StorageDevice device) {
			IAsyncResult result = device.BeginOpenContainer("StorageDemo", null, null);

			// Wait for the WaitHandle to become signaled.
			result.AsyncWaitHandle.WaitOne();

			StorageContainer container = device.EndOpenContainer(result);

			// Close the wait handle.
			result.AsyncWaitHandle.Close();

			// Add the container path to our file name.
			string filename = "demobinary.sav";

			Stream file = container.OpenFile(filename, FileMode.Open);
			file.Close();

			// Dispose the container.
			container.Dispose();
		}

		/// <summary>
		/// This method illustrates how to copy files. It presumes that demobinary.sav has been created.
		/// </summary>
		private void DoCopy(StorageDevice device) {
			IAsyncResult result = device.BeginOpenContainer("StorageDemo", null, null);

			// Wait for the WaitHandle to become signaled.
			result.AsyncWaitHandle.WaitOne();

			StorageContainer container = device.EndOpenContainer(result);

			// Close the wait handle.
			result.AsyncWaitHandle.Close();

			// Add the container path to our file name.
			string filename = "demobinary.sav";
			string copyfilename = "copybinary.sav";

			if (container.FileExists(filename) && !container.FileExists(copyfilename)) {
				Stream file = container.OpenFile(filename, FileMode.Open);
				Stream copyfile = container.CreateFile(copyfilename);
				file.CopyTo(copyfile);

				file.Close();
				copyfile.Close();
			}

			// Dispose the container, to commit the change.
			container.Dispose();
		}

		/// <summary>
		/// This method illustrates how to rename files. It presumes that demobinary.sav has been created.
		/// </summary>
		private void DoRename(StorageDevice device) {
			IAsyncResult result = device.BeginOpenContainer("StorageDemo", null, null);

			// Wait for the WaitHandle to become signaled.
			result.AsyncWaitHandle.WaitOne();

			StorageContainer container = device.EndOpenContainer(result);

			// Close the wait handle.
			result.AsyncWaitHandle.Close();

			// Add the container path to our file name.
			string oldfilename = "demobinary.sav";
			string newfilename = "renamebinary.sav";

			if (container.FileExists(oldfilename) && !container.FileExists(newfilename)) {
				Stream oldfile = container.OpenFile(oldfilename, FileMode.Open);
				Stream newfile = container.CreateFile(newfilename);
				oldfile.CopyTo(newfile);

				oldfile.Close();
				newfile.Close();
				container.DeleteFile(oldfilename);
			}

			// Dispose the container, to commit the change.
			container.Dispose();
		}

		/// <summary>
		/// This method deletes a file previously created by this demo.
		/// </summary>
		private void DoDelete(StorageDevice device) {
			IAsyncResult result = device.BeginOpenContainer("StorageDemo", null, null);

			// Wait for the WaitHandle to become signaled.
			result.AsyncWaitHandle.WaitOne();

			StorageContainer container = device.EndOpenContainer(result);

			// Close the wait handle.
			result.AsyncWaitHandle.Close();

			// Add the container path to our file name.
			string filename = "demobinary.sav";

			if (container.FileExists(filename)) {
				container.DeleteFile(filename);
			}

			// Dispose the container, to commit the change.
			container.Dispose();
		}

		/// <summary>
		/// This method opens a file using System.IO classes and the TitleLocation property.  
		/// It presumes that a file named ship.dds has been deployed alongside the game.
		/// </summary>
		private void DoOpenFile() {
			try {
				Stream stream = TitleContainer.OpenStream("ship.dds");
				StreamReader sreader = new StreamReader(stream);
				// use StreamReader.ReadLine or other methods to read the file data

				Console.WriteLine("File Size: "+stream.Length);
				stream.Close();
			} catch (FileNotFoundException) {
				// this will be thrown by OpenStream if gamedata.txt
				// doesn't exist in the title storage location
			}
		}

		//=====( End Files )=======================================================================

	}

}